﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Diagnostics;

using RaisingStudio.SmallProgram.Library.Internal;

namespace RaisingStudio.SmallProgram.Library
{
    [SmallProgramType]
    public static class GraphicsWindow
    {
        internal static SolidColorBrush _fillBrush = System.Windows.Media.Brushes.SlateBlue;
        private static System.Windows.Controls.Image _bitmapContainer;


        private static bool _isHidden;
        private static Key _lastKey;
        private static string _lastText;
        private static Canvas _mainCanvas;
        private static DrawingGroup _mainDrawing;

        internal static Dictionary<string, UIElement> _objectsMap = new Dictionary<string, UIElement>();
        private static Random _random;
        private static RenderTargetBitmap _renderBitmap;
        private static Dictionary<string, ScaleTransform> _scaleTransformMap = new Dictionary<string, ScaleTransform>();
        private const int _step = 20;
        private static object _syncLock = new object();
        private static VisualContainer _visualContainer;
        private static Window _window;
        internal static bool _windowCreated = false;
        internal static bool _windowVisible = false;

        private static SolidColorBrush _backgroundBrush;
        public static Primitive BackgroundColor
        {
            get
            {
                VerifyAccess();
                return (string)InvokeWithReturn(delegate
                {
                    return GetStringFromColor(_backgroundBrush.Color);
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _backgroundBrush = new SolidColorBrush(GetColorFromString((string)value));
                    _window.Background = _backgroundBrush;
                });
            }
        }

        public static Primitive BrushColor
        {
            get
            {
                VerifyAccess();
                return (string)InvokeWithReturn(delegate
                {
                    return GetStringFromColor(_fillBrush.Color);
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _fillBrush = new SolidColorBrush(GetColorFromString((string)value));
                    _fillBrush.Freeze();
                });
            }
        }

        public static Primitive CanResize
        {
            get
            {
                VerifyAccess();
                return (bool)InvokeWithReturn(delegate
                {
                    return _window.ResizeMode == ResizeMode.CanResize;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    if (value != 0)
                    {
                        _window.ResizeMode = ResizeMode.CanResize;
                    }
                    else
                    {
                        _window.ResizeMode = ResizeMode.NoResize;
                    }
                });
            }
        }

        internal static System.Windows.Media.FontFamily _fontFamily;
        private const string _defaultFontName = "Tahoma";
        public static Primitive FontName
        {
            get
            {
                return (string)InvokeWithReturn(delegate
                {
                    if (_fontFamily != null)
                    {
                        return _fontFamily.Source;
                    }
                    return "Tahoma";
                });
            }
            set
            {
                BeginInvoke(delegate
                {
                    _fontFamily = new System.Windows.Media.FontFamily((string)value);
                });
            }
        }

        internal static double _fontSize = 12.0;
        public static Primitive FontSize
        {
            get
            {
                return new Primitive(_fontSize);
            }
            set
            {
                BeginInvoke(delegate
                {
                    _fontSize = (double)value;
                });
            }
        }

        internal static FontWeight _fontWeight = FontWeights.Bold;
        public static Primitive FontBold
        {
            get
            {
                return (_fontWeight == FontWeights.Bold);
            }
            set
            {
                BeginInvoke(delegate
                {
                    if (value != 0)
                    {
                        _fontWeight = FontWeights.Bold;
                    }
                    else
                    {
                        _fontWeight = FontWeights.Normal;
                    }
                });
            }
        }

        internal static System.Windows.FontStyle _fontStyle = FontStyles.Normal;
        public static Primitive FontItalic
        {
            get
            {
                return (_fontStyle == FontStyles.Italic);
            }
            set
            {
                BeginInvoke(delegate
                {
                    if (value)
                    {
                        _fontStyle = FontStyles.Italic;
                    }
                    else
                    {
                        _fontStyle = FontStyles.Normal;
                    }
                });
            }
        }

        public static Primitive LastKey
        {
            get
            {
                return _lastKey.ToString();
            }
        }

        public static Primitive LastText
        {
            get
            {
                return _lastText.ToString();
            }
        }

        public static Primitive Left
        {
            get
            {
                VerifyAccess();
                return (double)InvokeWithReturn(delegate
                {
                    return _window.Left;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _window.Left = (double)value;
                });
            }
        }

        public static Primitive Top
        {
            get
            {
                VerifyAccess();
                return (double)InvokeWithReturn(delegate
                {
                    return _window.Top;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _window.Top = (double)value;
                });
            }
        }

        public static Primitive Width
        {
            get
            {
                VerifyAccess();
                return (double)InvokeWithReturn(delegate
                {
                    return _mainCanvas.ActualWidth;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _window.Width = value + (_window.ActualWidth - _mainCanvas.ActualWidth);
                });
            }
        }

        public static Primitive Height
        {
            get
            {
                VerifyAccess();
                return (double)InvokeWithReturn(delegate
                {
                    return _mainCanvas.ActualHeight;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _window.Height = value + (_window.ActualHeight - _mainCanvas.ActualHeight);
                });
            }
        }


        private static double _mouseX;
        public static Primitive MouseX
        {
            get
            {
                return _mouseX;
            }
        }

        private static double _mouseY;
        public static Primitive MouseY
        {
            get
            {
                return _mouseY;
            }
        }

        internal static System.Windows.Media.Pen _pen;
        public static Primitive PenColor
        {
            get
            {
                VerifyAccess();
                return (string)InvokeWithReturn(delegate
                {
                    if (_pen != null)
                    {
                        return GetStringFromColor(((SolidColorBrush)_pen.Brush).Color);
                    }
                    return "Black";
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _pen = new System.Windows.Media.Pen(new SolidColorBrush(GetColorFromString((string)value)), _pen.Thickness);
                    _pen.Freeze();
                });
            }
        }
        public static Primitive PenWidth
        {
            get
            {
                VerifyAccess();
                return (double)InvokeWithReturn(delegate
                {
                    if (_pen != null)
                    {
                        return _pen.Thickness;
                    }
                    return 2.0;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _pen = new System.Windows.Media.Pen(_pen.Brush, (double)value);
                    _pen.Freeze();
                });
            }
        }

        public static Primitive Title
        {
            get
            {
                VerifyAccess();
                return (string)InvokeWithReturn(delegate
                {
                    return _window.Title;
                });
            }
            set
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    _window.Title = (string)value;
                });
            }
        }

        
        private static SmallProgramCallback _keyDown;
        public static event SmallProgramCallback KeyDown
        {
            add
            {
                VerifyAccess();
                _keyDown = null;
                _keyDown += value;
            }
            remove
            {
                _keyDown -= value;
            }
        }

        private static SmallProgramCallback _keyUp;
        public static event SmallProgramCallback KeyUp
        {
            add
            {
                VerifyAccess();
                _keyUp = null;
                _keyUp += value;
            }
            remove
            {
                _keyUp -= value;
            }
        }

        private static SmallProgramCallback _mouseDown;
        public static event SmallProgramCallback MouseDown
        {
            add
            {
                VerifyAccess();
                _mouseDown = null;
                _mouseDown += value;
            }
            remove
            {
                _mouseDown -= value;
            }
        }

        private static SmallProgramCallback _mouseMove;
        public static event SmallProgramCallback MouseMove
        {
            add
            {
                VerifyAccess();
                _mouseMove = null;
                _mouseMove += value;
            }
            remove
            {
                _mouseMove -= value;
            }
        }

        private static SmallProgramCallback _mouseUp;
        public static event SmallProgramCallback MouseUp
        {
            add
            {
                VerifyAccess();
                _mouseUp = null;
                _mouseUp += value;
            }
            remove
            {
                _mouseUp -= value;
            }
        }

        private static SmallProgramCallback _textInput;
        public static event SmallProgramCallback TextInput
        {
            add
            {
                VerifyAccess();
                _textInput = null;
                _textInput += value;
            }
            remove
            {
                _textInput -= value;
            }
        }


        public static void Show()
        {
            if (!_windowCreated)
            {
                CreateWindow();
            }
            _isHidden = false;
            if (!_windowVisible)
            {
                Invoke(delegate
                {
                    _window.Show();
                });
                _windowVisible = true;
            }
        }

        public static void Hide()
        {
            _isHidden = true;
            if (_windowVisible)
            {
                Invoke(delegate
                {
                    _window.Hide();
                });
                _windowVisible = false;
            }
        }


        internal static void AddControl(string name, Control control)
        {
            VerifyAccess();
            control.Foreground = _fillBrush;
            control.FontFamily = _fontFamily;
            control.FontStyle = _fontStyle;
            control.FontSize = _fontSize;
            control.FontWeight = _fontWeight;
            AddShape(name, control);
        }

        internal static void AddRasterizeOperationToQueue()
        {
            if (_mainDrawing.Children.Count > 100)
            {
                Rasterize();
            }
        }

        internal static void AddShape(string name, FrameworkElement shape)
        {
            VerifyAccess();
            shape.Name = name;
            _objectsMap[name] = shape;
            _mainCanvas.Children.Add(shape);
        }

        internal static void BeginInvoke(InvokeHelper invokeDelegate)
        {
            SmallProgramApplication.BeginInvoke(invokeDelegate);
        }


        public static void Clear()
        {
            VerifyAccess();
            Invoke(delegate
            {
                _mainCanvas.Children.Clear();
                _renderBitmap.Clear();
                _mainDrawing.Children.Clear();
                _objectsMap.Clear();
            });
        }

        internal static bool ContainsShape(string name)
        {
            return _objectsMap.ContainsKey(name);
        }

        private static void CreateWindow()
        {
            lock (_syncLock)
            {
                Invoke(delegate
                {
                    _window = new Window();
                    _windowCreated = true;
                    _window.Title = "Small Program Graphics Window";
                    if (_backgroundBrush == null)
                    {
                        _backgroundBrush = System.Windows.Media.Brushes.White;
                    }
                    _window.Background = _backgroundBrush;
                    if (_fillBrush == null)
                    {
                        _fillBrush = System.Windows.Media.Brushes.CornflowerBlue;
                    }
                    if (_pen == null)
                    {
                        _pen = new System.Windows.Media.Pen(System.Windows.Media.Brushes.Black, 2.0);
                    }
                    if (_fontFamily == null)
                    {
                        _fontFamily = new System.Windows.Media.FontFamily("Tahoma");
                    }
                    _window.Height = 480.0;
                    _window.Width = 640.0;
                    if (!_isHidden)
                    {
                        _window.Show();
                    }
                    _window.SourceInitialized += delegate
                    {
                        IntPtr handle = ((HwndSource)PresentationSource.FromVisual(_window)).Handle;
                        uint dwNewLong = (NativeHelper.GetWindowLong(handle, NativeHelper.GWL_STYLE) & 0xfffeffff) | NativeHelper.WS_MINIMIZEBOX;
                        NativeHelper.SetWindowLong(handle, NativeHelper.GWL_STYLE, dwNewLong);
                        RaisingStudio.SmallProgram.Library.Internal.RECT rect2 = new RaisingStudio.SmallProgram.Library.Internal.RECT
                        {
                            Left = 0,
                            Top = 0,
                            Right = (int)_window.Width,
                            Bottom = (int)_window.Height
                        };
                        RaisingStudio.SmallProgram.Library.Internal.RECT lpRect = rect2;
                        NativeHelper.AdjustWindowRect(ref lpRect, dwNewLong, false);
                        _window.Width = lpRect.Right - lpRect.Left;
                        _window.Height = lpRect.Bottom - lpRect.Top;
                        NativeHelper.SetForegroundWindow(handle);
                    };
                    SetWindowContent();
                    SignupForWindowEvents();
                    _window.UpdateLayout();
                });
            }
        }

        internal static void DoubleAnimateProperty(IAnimatable animatable, DependencyProperty property, double end, double timespan)
        {
            double value = (double)((DependencyObject)animatable).GetValue(property);
            if (double.IsNaN(value))
            {
                value = 0.0;
            }
            DoubleAnimation animation = new DoubleAnimation(value, end, new Duration(TimeSpan.FromMilliseconds(timespan)));
            animation.FillBehavior = FillBehavior.HoldEnd;
            animation.DecelerationRatio = 0.2;
            animatable.BeginAnimation(property, animation);
        }


        public static void DrawBoundText(Primitive x, Primitive y, Primitive width, Primitive text)
        {
            if (!text.IsEmpty)
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    DrawingContext context = _mainDrawing.Append();
                    FormattedText formattedText = new FormattedText((string)text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(_fontFamily, _fontStyle, _fontWeight, FontStretches.Normal), _fontSize, _fillBrush)
                    {
                        MaxTextWidth = (double)width
                    };
                    context.DrawText(formattedText, new System.Windows.Point((double)x, (double)y));
                    context.Close();
                    AddRasterizeOperationToQueue();
                });
            }
        }

        public static void DrawEllipse(Primitive x, Primitive y, Primitive width, Primitive height)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                context.DrawEllipse(null, _pen, new System.Windows.Point((double)(x + (width / 2)), (double)(y + (height / 2))), (double)(width / 2), (double)(height / 2));
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }

        public static void DrawImage(Primitive imageName, Primitive x, Primitive y)
        {
            if (!imageName.IsEmpty)
            {
                VerifyAccess();
                BitmapSource image = ImageList.GetBitmap(imageName);
                if (image != null)
                {
                    BeginInvoke(delegate
                    {
                        DrawingContext context = _mainDrawing.Append();
                        context.DrawImage(image, new Rect((double)x, (double)y, (double)image.PixelWidth, (double)image.PixelHeight));
                        context.Close();
                        AddRasterizeOperationToQueue();
                    });
                }
            }
        }


        public static void DrawImage(Primitive imageName, Primitive x, Primitive y, Primitive width, Primitive height)
        {
            if (!imageName.IsEmpty)
            {
                VerifyAccess();
                BitmapSource image = ImageList.GetBitmap(imageName);
                if (image != null)
                {
                    BeginInvoke(delegate
                    {
                        DrawingContext context = _mainDrawing.Append();
                        context.DrawImage(image, new Rect((double)x, (double)y, (double)width, (double)height));
                        context.Close();
                        AddRasterizeOperationToQueue();
                    });
                }
            }
        }

        public static void DrawImage(Primitive imageName, Primitive x, Primitive y, Primitive width, Primitive height, Primitive src_x, Primitive src_y)
        {
            if (!imageName.IsEmpty)
            {
                VerifyAccess();
                BitmapSource image = ImageList.GetBitmap(imageName);
                if (image != null)
                {
                    BeginInvoke(delegate
                    {
                        DrawingContext context = _mainDrawing.Append();
                        CroppedBitmap cb = new CroppedBitmap(image, new Int32Rect((int)src_x, (int)src_y, image.PixelWidth - (int)src_x, image.PixelHeight - (int)src_y));
                        context.DrawImage(cb, new Rect((double)x, (double)y, (double)width, (double)height));
                        context.Close();
                        AddRasterizeOperationToQueue();
                    });
                }
            }
        }

        public static void DrawLine(Primitive x1, Primitive y1, Primitive x2, Primitive y2)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                context.DrawLine(_pen, new System.Windows.Point((double)x1, (double)y1), new System.Windows.Point((double)x2, (double)y2));
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }

        public static void DrawRectangle(Primitive x, Primitive y, Primitive width, Primitive height)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                context.DrawRectangle(null, _pen, new Rect((double)x, (double)y, (double)width, (double)height));
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }

        public static void DrawResizedImage(Primitive imageName, Primitive x, Primitive y, Primitive width, Primitive height)
        {
            if (!imageName.IsEmpty)
            {
                VerifyAccess();
                BitmapSource image = ImageList.GetBitmap(imageName);
                if (image != null)
                {
                    BeginInvoke(delegate
                    {
                        DrawingContext context = _mainDrawing.Append();
                        context.DrawImage(image, new Rect((double)x, (double)y, (double)width, (double)height));
                        context.Close();
                        AddRasterizeOperationToQueue();
                    });
                }
            }
        }

        public static void DrawText(Primitive x, Primitive y, Primitive text)
        {
            if (!text.IsEmpty)
            {
                VerifyAccess();
                BeginInvoke(delegate
                {
                    DrawingContext context = _mainDrawing.Append();
                    FormattedText formattedText = new FormattedText((string)text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(_fontFamily, _fontStyle, _fontWeight, FontStretches.Normal), _fontSize, _fillBrush);
                    context.DrawText(formattedText, new System.Windows.Point((double)x, (double)y));
                    context.Close();
                    AddRasterizeOperationToQueue();
                });
            }
        }

        public static void DrawTriangle(Primitive x1, Primitive y1, Primitive x2, Primitive y2, Primitive x3, Primitive y3)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                PathFigure figure = new PathFigure
                {
                    StartPoint = new System.Windows.Point((double)x1, (double)y1),
                    IsClosed = true,
                    Segments = { new LineSegment(new System.Windows.Point((double)x2, (double)y2), true), new LineSegment(new System.Windows.Point((double)x3, (double)y3), true) }
                };
                PathFigureCollection figures = new PathFigureCollection {
                    figure
                };
                PathGeometry geometry = new PathGeometry
                {
                    Figures = figures
                };
                geometry.Freeze();
                context.DrawGeometry(null, _pen, geometry);
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }

        public static void FillEllipse(Primitive x, Primitive y, Primitive width, Primitive height)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                context.DrawEllipse(_fillBrush, null, new System.Windows.Point((double)(x + (width / 2)), (double)(y + (height / 2))), (double)(width / 2), (double)(height / 2));
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }

        public static void FillRectangle(Primitive x, Primitive y, Primitive width, Primitive height)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                context.DrawRectangle(_fillBrush, null, new Rect((double)x, (double)y, (double)width, (double)height));
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }

        public static void FillTriangle(Primitive x1, Primitive y1, Primitive x2, Primitive y2, Primitive x3, Primitive y3)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                PathFigure figure = new PathFigure
                {
                    StartPoint = new System.Windows.Point((double)x1, (double)y1),
                    IsClosed = true,
                    Segments = { new LineSegment(new System.Windows.Point((double)x2, (double)y2), true), new LineSegment(new System.Windows.Point((double)x3, (double)y3), true) }
                };
                PathFigureCollection figures = new PathFigureCollection
                {
                    figure
                };
                PathGeometry geometry = new PathGeometry
                {
                    Figures = figures
                };
                geometry.Freeze();
                context.DrawGeometry(_fillBrush, null, geometry);
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }


        public static Primitive GetColorFromRGB(Primitive red, Primitive green, Primitive blue)
        {
            int r = System.Math.Abs((int)(red % 0x100));
            int g = System.Math.Abs((int)(green % 0x100));
            int b = System.Math.Abs((int)(blue % 0x100));
            return string.Format("#{0:X2}{1:X2}{2:X2}", r, g, b);
        }

        internal static System.Windows.Media.Color GetColorFromString(string color)
        {
            try
            {
                return (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(color);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
            return Colors.Black;
        }

        public static Primitive GetPixel(Primitive x, Primitive y)
        {
            VerifyAccess();
            return (Primitive)InvokeWithReturn(delegate
            {
                Rasterize();
                byte[] pixels = new byte[4];
                int stride = ((int)_renderBitmap.Width) * ((_renderBitmap.Format.BitsPerPixel + 7) / 8);
                _renderBitmap.CopyPixels(new Int32Rect((int)x, (int)y, 1, 1), pixels, stride, 0);
                return (Primitive)string.Format("#{0:X2}{1:X2}{2:X2}", pixels[2], pixels[1], pixels[0]);
            });
        }

        public static void SetPixel(Primitive x, Primitive y, Primitive color)
        {
            VerifyAccess();
            BeginInvoke(delegate
            {
                DrawingContext context = _mainDrawing.Append();
                context.DrawRectangle(new SolidColorBrush(GetColorFromString((string)color)), null, new Rect((double)x, (double)y, 1.0, 1.0));
                context.Close();
                AddRasterizeOperationToQueue();
            });
        }


        public static Primitive GetRandomColor()
        {
            if (_random == null)
            {
                _random = new Random((int)DateTime.Now.Ticks);
            }
            return string.Format("#{0:X2}{1:X2}{2:X2}", _random.Next(0x100), _random.Next(0x100), _random.Next(0x100));
        }

        internal static string GetStringFromColor(System.Windows.Media.Color color)
        {
            return ColorTranslator.ToHtml(System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B));
        }

        internal static void Invoke(InvokeHelper invokeDelegate)
        {
            SmallProgramApplication.Invoke(invokeDelegate);
        }

        internal static object InvokeWithReturn(InvokeHelperWithReturn invokeDelegate)
        {
            return SmallProgramApplication.InvokeWithReturn(invokeDelegate);
        }

        private static void Rasterize()
        {
            if (_mainDrawing.Children.Count != 0)
            {
                _renderBitmap.Render(_visualContainer);
                _mainDrawing.Children.Clear();
            }
        }

        internal static void RemoveShape(Primitive name)
        {
            UIElement shape = null;
            if (_objectsMap.TryGetValue((string)name, out shape))
            {
                _objectsMap.Remove((string)name);
                Invoke(delegate
                {
                    _mainCanvas.Children.Remove(shape);
                });
            }
        }

        internal static void SetCursor(Cursor cursor)
        {
            VerifyAccess();
            Invoke(delegate
            {
                _window.Cursor = cursor;
            });
        }

        private static void SetWindowContent()
        {
            _mainCanvas = new Canvas();
            _mainCanvas.HorizontalAlignment = HorizontalAlignment.Stretch;
            _mainCanvas.VerticalAlignment = VerticalAlignment.Stretch;
            _renderBitmap = new RenderTargetBitmap(((int)_window.Width) + 120, ((int)_window.Height) + 120, 96.0, 96.0, PixelFormats.Default);
            System.Windows.Controls.Image image = new System.Windows.Controls.Image();
            image.Source = _renderBitmap;
            image.Stretch = Stretch.None;
            _bitmapContainer = image;
            _mainDrawing = new DrawingGroup();
            _visualContainer = new VisualContainer(_mainDrawing);
            Grid grid = new Grid();
            grid.Children.Add(_bitmapContainer);
            grid.Children.Add(_visualContainer);
            grid.Children.Add(_mainCanvas);
            _window.Content = grid;
        }


        public static void ShowMessage(Primitive text, Primitive title)
        {
            VerifyAccess();
            Invoke(delegate
            {
                MessageBox.Show(_window, (string)text, (string)title);
            });
        }

        private static void SignupForWindowEvents()
        {
            _window.SizeChanged += new SizeChangedEventHandler(GraphicsWindow.WindowSizeChanged);
            _window.Closing += new CancelEventHandler(GraphicsWindow.WindowClosing);
            _window.MouseDown += delegate
            {
                SmallProgramCallback mouseDown = _mouseDown;
                if (mouseDown != null)
                {
                    mouseDown();
                }
            };
            _window.MouseUp += delegate
            {
                SmallProgramCallback mouseUp = _mouseUp;
                if (mouseUp != null)
                {
                    mouseUp();
                }
            };
            _window.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                SmallProgramCallback mouseMove = _mouseMove;
                System.Windows.Point position = e.GetPosition(_mainCanvas);
                _mouseX = position.X;
                _mouseY = position.Y;
                if (mouseMove != null)
                {
                    mouseMove();
                }
            };
            _window.KeyDown += delegate(object sender, KeyEventArgs e)
            {
                SmallProgramCallback keyDown = _keyDown;
                _lastKey = e.Key;
                if (keyDown != null)
                {
                    BeginInvoke(delegate
                        {
                            keyDown();
                        });
                }
            };
            _window.TextInput += delegate(object sender, TextCompositionEventArgs e)
            {
                SmallProgramCallback textInput = _textInput;
                _lastText = e.Text;
                if (textInput != null)
                {
                    BeginInvoke(delegate
                        {
                            textInput();
                        });
                }
            };
            _window.KeyUp += delegate(object sender, KeyEventArgs e)
            {
                SmallProgramCallback keyUp = _keyUp;
                _lastKey = e.Key;
                if (keyUp != null)
                {

                    BeginInvoke(delegate
                        {
                            keyUp();
                        });
                }
            };
        }

        internal static void VerifyAccess()
        {
            if (!_windowCreated)
            {
                CreateWindow();
                if (!_isHidden)
                {
                    Show();
                }
            }
        }

        private static void WindowClosing(object sender, CancelEventArgs e)
        {
            SmallProgramApplication.End();
        }

        private static void WindowSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if ((e.NewSize.Width > _renderBitmap.Width) || (e.NewSize.Height > _renderBitmap.Height))
            {
                RenderTargetBitmap imageSource = _renderBitmap;
                _renderBitmap = new RenderTargetBitmap(((int)e.NewSize.Width) + 120, ((int)e.NewSize.Height) + 120, 96.0, 96.0, PixelFormats.Default);
                DrawingVisual visual = new DrawingVisual();
                DrawingContext context = visual.RenderOpen();
                context.DrawImage(imageSource, new Rect(0.0, 0.0, imageSource.Width, imageSource.Height));
                context.Close();
                _renderBitmap.Render(visual);
                _bitmapContainer.Width = _renderBitmap.Width;
                _bitmapContainer.Height = _renderBitmap.Height;
                _bitmapContainer.Source = _renderBitmap;
                _bitmapContainer.Stretch = Stretch.None;
            }
        }

        private class VisualContainer : FrameworkElement
        {
            private Drawing _drawing;

            public VisualContainer(Drawing drawing)
            {
                this._drawing = drawing;
            }

            protected override void OnRender(DrawingContext drawingContext)
            {
                drawingContext.DrawDrawing(this._drawing);
            }
        }
    }
}

